package com.lsh.streamgd.http;

import com.lsh.streamgd.utils.StringUtil;

import java.util.HashMap;
import java.util.Map;

/**
 * <li><b>网络访问参数的上下文</b>,支持post,get,put,delete</li>
 * <li>支持url路径内传参,支持url key=value传参,支持request body内key=vlue和json传参</li>
 * <li>咱不支持文件上传</li>
 *
 * @author liujingui
 * @ClassName: NetWorkContext
 * @date 2016年3月3日 下午12:34:01
 * @see HttpRequest
 */
public class NetWorkContext {

    public static final String CONTENTTYPE_WEB = "application/x-www-form-urlencoded; charset=UTF-8";
    public static final String CONTENTTYPE_JSON = "application/json; charset=UTF-8";
    private String url;
    private String method;
    private String pathParams;
    private String bodyParams;
    private boolean isproxy;
    private Map<String, String> headers;
    private Map<String, String> innerPathParams;
    private Response resp;

    private NetWorkContext() {
        headers = new HashMap<>();
        headers.put("User-Agent", "Rank-Server");
        headers.put("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
        headers.put("Cache-Control", "max-age=0");
        headers.put("connection", "Keep-Alive");
        headers.put("accept", "*/*");
        headers.put("content-type", CONTENTTYPE_JSON);
    }

    private static NetWorkContext init(String url, String method) {
        if (StringUtil.hasBlank(url, method)) {
            throw new IllegalArgumentException("url and method should be defined corretly!");
        }
        if (!url.contains("http")) {
            throw new IllegalArgumentException("only support for 'http(s)' protocol!");
        }
        NetWorkContext context = new NetWorkContext();
        context.url = url;
        context.method = method;
        return context;
    }

    public static NetWorkContext post(String url) {
        return init(url, "POST");
    }

    public static NetWorkContext get(String url) {
        return init(url, "GET");
    }

    public static NetWorkContext put(String url) {
        return init(url, "PUT");
    }

    public static NetWorkContext delete(String url) {
        return init(url, "DELETE");
    }

    /**
     * 传入key1=value1&key2=value2的参数
     *
     * @param pathParams
     * @return NetWorkContext
     * @author liujingui
     * @date 2016年5月3日 上午10:36:35
     */
    public NetWorkContext addPathParams(String pathParams) {
        if (StringUtil.isBlank(pathParams)) return this;
        if (this.pathParams == null) this.pathParams = "";
        this.pathParams = pathParams.charAt(0) == '&' ? this.pathParams + pathParams : this.pathParams + "&" + pathParams;
        if (this.pathParams.charAt(0) == '&') {
            this.pathParams = this.pathParams.substring(1, this.pathParams.length());
        }
        return this;
    }

    /**
     * 传入key=value的url路径参数
     *
     * @param key
     * @param value
     * @return
     */
    public NetWorkContext addPathParams(String key, String value) {
        if (StringUtil.hasBlank(key, value)) {
            throw new IllegalArgumentException("key or value is invalid");
        }
        return addPathParams(key + "=" + value);
    }

    /**
     * 传入key=value的url路径参数
     *
     * @param key
     * @param value
     * @return
     */
    public NetWorkContext addPathParams(String key, Object value) {
        if (value == null) {
            throw new IllegalArgumentException("value cannot be null");
        }
        return addPathParams(key, String.valueOf(value));
    }

    /**
     * 以对象形式传入key1=value1&key2=value2的参数
     *
     * @param pathParamObj
     * @return NetWorkContext
     * @author liujingui
     * @date 2016年5月3日 上午10:36:35
     */
    public NetWorkContext addPathParams(Object pathParamObj, String[] excludedKeys) {
        if (pathParamObj == null) return this;
        if (this.pathParams == null) this.pathParams = "";
        this.pathParams += "&" + StringUtil.getKeyValueStr(pathParamObj, excludedKeys);
        if (this.pathParams.charAt(0) == '&') {
            this.pathParams = this.pathParams.substring(1, this.pathParams.length());
        }
        return this;
    }

    /**
     * 设置url路径内的参数
     *
     * @param key,value
     * @return NetWorkContext
     * @author liujingui
     * @date 2016年5月3日 上午10:36:35
     */
    public NetWorkContext addInnerPathParams(String key, String value) {
        if (null == innerPathParams) innerPathParams = new HashMap<>();
        this.innerPathParams.put(key, value);
        return this;
    }

    public NetWorkContext setContentType(String contentType) {
        headers.put("content-type", contentType);
        return this;
    }

    private void checkIfCanSetPostParams() {
        if ("GET".equals(method)) {
            throw new IllegalArgumentException("cannot set post parameters under GET method");
        }
    }

    /**
     * 以字符串形式设置传递body中的参数,content-type默认为json格式,使用者自己注意要对应传入的字符串格式
     * json格式的参数只能设置一次,而web形式的参数可设置多次
     *
     * @param bodyParams
     * @return
     */
    public NetWorkContext addPostParams(String bodyParams) {
        return addPostParams(null, bodyParams);
    }

    /**
     * 以字符串形式设置传递body中的参数,content-type应当对应字符串形式(未检查字符串格式,使用者自己注意)
     *json格式的参数只能设置一次,而web形式的参数可设置多次
     *
     * @param contentType 请求header的content-type
     * @param bodyParams  参数对象
     * @return NetWorkContext
     * @author liujingui
     * @date 2016年3月10日 下午12:23:24
     */
    public NetWorkContext addPostParams(String contentType, String bodyParams) {
        if (StringUtil.isBlank(bodyParams)) return this;
        checkIfCanSetPostParams();
        if (!StringUtil.isBlank(contentType)) {
            setContentType(contentType);
        }
        String settedContentType = headers.get("content-type");
        if (this.bodyParams == null) {
            this.bodyParams = "";
        }
        if (CONTENTTYPE_WEB.equals(settedContentType)) {
            this.bodyParams = bodyParams.charAt(0) == '&' ? this.bodyParams + bodyParams : this.bodyParams + "&" + bodyParams;
            if (this.bodyParams.charAt(0) == '&') {
                this.bodyParams = this.bodyParams.substring(1, this.bodyParams.length());
            }
        } else if (CONTENTTYPE_JSON.equals(settedContentType)) {
            if (!StringUtil.isBlank(this.bodyParams)) {
                throw new IllegalArgumentException("json body only can be set once,you have already set the json body!");
            }
            this.bodyParams = bodyParams;
        }
        return this;
    }

    /**
     * 以对象形式设置传递body中的的参数,之后被转成content-type(默认json格式)对应的字符串
     *json格式的参数只能设置一次,而web形式的参数可设置多次
     *
     * @param bodyParamsObj
     * @param excludedKeys
     * @return
     */
    public NetWorkContext addPostParams(Object bodyParamsObj, String[] excludedKeys) {
        return addPostParams(null, bodyParamsObj, excludedKeys);
    }

    /**
     * 以对象形式设置传递body中的的参数,之后被转成content-type对应的字符串
     *json格式的参数只能设置一次,而web形式的参数可设置多次
     *
     * @param contentType   请求header的content-type
     * @param bodyParamsObj 参数对象
     * @return NetWorkContext
     * @author liujingui
     * @date 2016年3月10日 下午12:23:24
     */
    public NetWorkContext addPostParams(String contentType, Object bodyParamsObj, String[] excludedKeys) {
        if (bodyParamsObj == null) return this;
        checkIfCanSetPostParams();
        if (!StringUtil.isBlank(contentType)) {
            setContentType(contentType);
        }
        String settedContentType = headers.get("content-type");
        if (this.bodyParams == null) this.bodyParams = "";
        if (CONTENTTYPE_JSON.equals(settedContentType)) {
            if (!StringUtil.isBlank(this.bodyParams)) {
                throw new IllegalArgumentException("json body only can be set onece,you have already set the json body!");
            }
            this.bodyParams = StringUtil.getJSONDefault(bodyParamsObj);
        } else if (CONTENTTYPE_WEB.equals(settedContentType)) {
            this.bodyParams += "&" + StringUtil.getKeyValueStr(bodyParamsObj, excludedKeys);
            if (this.bodyParams.charAt(0) == '&') {
                this.bodyParams = this.bodyParams.substring(1, this.bodyParams.length());
            }
        }
        return this;
    }

    /**
     * 以MAP形式设置传递body中的的参数,之后被转成content-type对应的字符串
     *
     * @param contentType   请求header的content-type
     * @param bodyParamsMap 参数对象
     * @return NetWorkContext
     * @author gaoxu
     * @date 2017年4月10日 下午12:23:24
     */
    public NetWorkContext addPostParams(String contentType, Map bodyParamsMap) {
        if (bodyParamsMap == null) return this;
        checkIfCanSetPostParams();
        setContentType(contentType);
        if (this.bodyParams == null) this.bodyParams = "";
        if (CONTENTTYPE_JSON.equals(contentType)) {
            if (!StringUtil.isBlank(this.bodyParams)) {
                throw new IllegalArgumentException("json body only can be set onece,you have already set the json body!");
            }
            this.bodyParams = StringUtil.getJSONDefault(bodyParamsMap);
        } else if (CONTENTTYPE_WEB.equals(contentType)) {
            this.bodyParams += "&" + StringUtil.getKeyValueStr(bodyParamsMap);
        }
        return this;
    }

    public NetWorkContext setReqHeader(String key, String value) {
        headers.put(key, value);
        return this;
    }

    public String getUrl() {

        return url;
    }

    public String getMethod() {

        return method;
    }

    public String getPathParams() {

        return pathParams;
    }

    public String getBodyParams() {

        return bodyParams;
    }

    public Map<String, String> getHeaders() {

        return headers;
    }

    public Map<String, String> getInnerPathParams() {

        return innerPathParams;
    }

    public Response getResp() {
        if (resp == null || resp.code == 0 || resp.respBody == null) {
            throw new IllegalStateException("the request not finished or cannot received the response!");
        }
        return resp;
    }

    private void initResp() {
        Response resp = new Response();
        this.resp = resp;
    }

    public NetWorkContext setRespCode(int code) {
        if (resp == null) {
            initResp();
        }
        resp.code = code;
        return this;
    }

    public NetWorkContext setRespBody(String respBody) {
        if (resp == null) {
            initResp();
        }
        resp.respBody = respBody;
        return this;
    }

    public class Response {

        private int code;
        private String respBody;

        private Response() {
        }

        @Override
        public String toString() {
            return "Response [code=" + code + ", respBody=" + respBody + "]";
        }

        public int getCode() {

            return code;
        }

        public String getRespBody() {

            return respBody;
        }
    }

    public boolean isIsproxy() {
        return isproxy;
    }

    public NetWorkContext setIsproxy(boolean isproxy) {
        this.isproxy = isproxy;
        return this;
    }
}
